import { EventsRes, ICurve, SceneGraph } from '@amcax/base';
import { wsApi } from '@app-cad/server';
import { Vector2tuple, Vector3 } from 'three-legacy';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import CmdBase, { PickType } from '../../CmdBase';
import { MouseState, State } from './types';
import {
  calculatePoint,
  getAngle,
  getLineIntersectionTwo,
  isEffectiveValue,
  isEquals,
} from '@app-cad/common/utils';
import { dimension } from '../dimension/Dimension';
import { ctx2 } from '@app-cad/module';
import { sketchStore } from '@app-base/common/utils/sketchTools/useSketchStore';
import { loadEmit } from '@app-base/common/events/CoreEvent';

type SnapType = {
  curveId: string;
  pickType: PickType;
  point?: Vector3;
};
export default class CmdThreePointArcInteractor extends CmdBase {
  startPoint: Vector3; // 绘制起点
  secPoint: Vector3; // 绘制第二点
  endPoint: Vector3; // 绘制第三点
  startAngle: number; // 起始角度
  endAngle: number; // 结束角度
  currentState: MouseState = State.NONE;
  private startSnapPoint: SnapType;
  private secSnapPoint: SnapType;
  private threePoint: (Vector2tuple | string)[] = new Array(3);
  private isClockWise: boolean = true;
  private xRaduis: number = 0;
  private xCenter: Vector3;
  private center: Vector3;
  constructor(
    public onFinishDraw?: (curve: ICurve, point: string) => void,
    public allowContinuousCreate = false,
    public needSetEventCenterState = true,
  ) {
    super();
    this.registerEvents();
  }

  reset() {
    this.currentState = State.NONE;
    this.startPoint = null;
    this.secPoint = null;
    this.endPoint = null;
    this.startSnapPoint = null;
    this.secSnapPoint = null;
    this.threePoint = [];
    this.isClockWise = null;
    this.xRaduis = 0;
    this.xCenter = null;
    this.center = null;
  }

  registerEvents() {
    if (this.needSetEventCenterState) {
      sketchEventCenter().setState('SketchCircle');
    }
    sketchEventCenter()
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
  }

  unregisterEvents() {
    if (this.needSetEventCenterState) {
      sketchEventCenter().setDefault();
    }
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp);
  }

  releaseObjects() {
    dimension().destroy();
    this.assisGroup.clear();
    this.clearLine();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }

  onMouseMove = (e: EventsRes) => {
    this.setMouseWV(e, true);
    if (this.currentState === State.NONE) {
      return;
    }
    if (this.currentState === State.DRAW_CIRCLE) {
      this.secPoint = this.mouseWV.clone();
    } else if (this.currentState === State.DRAW_ARC) {
      this.endPoint = this.mouseWV.clone();
    }
    this.createAssistPoint(this.mouseWV.clone(), true);
    this.preview();
  };

  // 判断点是否重复
  isRepeatPoint = (point: Vector2tuple | string) => {
    return this.threePoint.some((item) => {
      if (typeof item === 'string') {
        return item === point;
      }
      return isEquals(item, point);
    });
  };

  setStartPoint(point: string) {
    this.threePoint = [point];
    const pointData = sketchStore.getState().curves.find((c) => c.id === point);

    this.startPoint = new Vector3(...pointData.vertices[0]);
    this.currentState = State.DRAW_CIRCLE;
  }

  onMouseDown = (e: EventsRes) => {
    if (e.button.onLeft && this.currentState !== State.FINISH) {
      const point: Vector2tuple | string =
        this.pickType === PickType.Point
          ? this.pickSnapInfo.id
          : [this.mouseWV.x, this.mouseWV.y];
      if (this.isRepeatPoint(point)) {
        return;
      }
      // 鼠标左键，进行绘制
      if (this.currentState === State.NONE) {
        this.threePoint[0] = point;
        this.startPoint = this.mouseWV.clone();
        this.previewLines.line = null;
        if (this.pickType !== PickType.Null) {
          this.startSnapPoint = {
            pickType: this.pickType,
            curveId: this.pickSnapInfo.id,
            point: this.mouseWV.clone(),
          };
        }
        this.currentState = State.DRAW_CIRCLE;
      } else if (this.currentState === State.DRAW_CIRCLE) {
        this.threePoint[2] = point;
        this.secPoint = this.mouseWV.clone();
        if (this.pickType !== PickType.Null) {
          this.secSnapPoint = {
            pickType: this.pickType,
            curveId: this.pickSnapInfo.id,
            point: this.mouseWV.clone(),
          };
        }
        this.currentState = State.DRAW_ARC;
      } else if (this.currentState === State.DRAW_ARC) {
        this.threePoint[1] = point;
        this.endPoint = this.mouseWV.clone();
        this.currentState = State.FINISH;
        this.finishDraw();
      }
      this.createAssistPoint(this.mouseWV.clone());
    } else if (e.button.onRight && !this.closeRightClick) {
      this.currentState = State.NONE;
      // 鼠标右键，取消绘制
      this.destroy();
    }
  };

  preview() {
    if (
      this.currentState === State.NONE ||
      this.currentState === State.FINISH
    ) {
      return;
    }
    const circleInfo = this.getCircleInfo();
    if (
      circleInfo &&
      isEffectiveValue(circleInfo.center) &&
      isEffectiveValue(circleInfo.radius)
    ) {
      this.createAssistPoint(circleInfo.center, true, 1);
      // // 绘制圆
      let params = {
        x: circleInfo.center.x,
        y: circleInfo.center.y,
        radius: circleInfo.radius,
        startAngle: 0,
        endAngle: Math.PI * 2,
        clockWise: this.isClockWise,
      };
      if (this.currentState === State.DRAW_CIRCLE) {
        this.createUpdateLine([this.startPoint, this.secPoint], 'xline', 1, {
          dashSize: 5,
          gapSize: 3,
        });
        this.createUpdateLine(this.getArcVertexs(params), 'rline', 1, {
          color: '#1683e8',
          dashSize: 8,
          gapSize: 3,
        });
      } else if (this.currentState === State.DRAW_ARC) {
        this.center = circleInfo.center;
        this.isClockWise = this.getPointPosition(
          this.startPoint,
          this.secPoint,
          this.endPoint,
        );
        this.startAngle = getAngle(this.startPoint, circleInfo.center);
        this.endAngle = getAngle(this.secPoint, circleInfo.center);
        this.clearLine();
        params = Object.assign(params, {
          startAngle: this.startAngle,
          endAngle: this.endAngle,
          clockWise: this.isClockWise,
        });
        this.createUpdateLine(this.getArcVertexs(params), 'line');
        dimension().dimRadius(
          circleInfo.center,
          this.isClockWise
            ? [this.secPoint, this.startPoint]
            : [this.startPoint, this.secPoint],
          circleInfo.radius,
        ); // 画半径
      }
      ctx2.viewer.requestRender();
    }
  }

  // 获取圆弧的中心点等信息
  getCircleInfo() {
    if (this.currentState === State.DRAW_CIRCLE) {
      this.xCenter = new Vector3()
        .addVectors(this.startPoint, this.secPoint)
        .divideScalar(2);
      this.xRaduis = this.xCenter.distanceTo(this.startPoint);
      return {
        center: this.xCenter,
        radius: this.xRaduis,
      };
    } else if (this.currentState === State.DRAW_ARC) {
      const center1 = new Vector3()
        .addVectors(this.startPoint, this.secPoint)
        .divideScalar(2);
      const center2 = new Vector3()
        .addVectors(this.secPoint, this.endPoint)
        .divideScalar(2);
      const vec1 = new Vector3()
        .subVectors(this.startPoint, this.secPoint)
        .normalize();
      const vec2 = new Vector3()
        .subVectors(this.secPoint, this.endPoint)
        .normalize();
      if (isEquals(vec1, vec2)) {
        return null;
      }
      const v1 = new Vector3(vec1.y, -vec1.x, 0);
      const v2 = new Vector3(vec2.y, -vec2.x, 0);
      const p1 = calculatePoint(v1, 1, center1);
      const p2 = calculatePoint(v2, 1, center2);
      const center3 = getLineIntersectionTwo(center1, p1, center2, p2);
      const center = new Vector3(center3.x, center3.y, 0);
      return {
        center,
        radius: center.distanceTo(this.startPoint),
      };
    }
    return null;
  }

  enterKeyDown = () => {
    if (this.currentState === State.DRAW_ARC) {
      const flag = dimension().determineDim(this.xRaduis);
      if (flag) {
        this.setRadius();
        this.preview();
        this.currentState = State.FINISH;
        setTimeout(() => {
          this.finishDraw();
        }, 10);
      }
    }
  };

  setRadius() {
    if (dimension().dimType === 'create') {
      this.endPoint = this.getArcVertex();
      this.threePoint[1] = [this.endPoint.x, this.endPoint.y];
    }
  }

  // 获取圆弧的顶点
  getArcVertex() {
    const r = dimension().getDimInfo().value;
    const c = this.getPointPosition(
      this.startPoint,
      this.secPoint,
      this.center,
    );
    const x =
      Math.sqrt(r ** 2 - this.xRaduis ** 2) *
        (c === this.isClockWise ? 1 : -1) || 0;
    const vec = new Vector3()
      .subVectors(this.startPoint, this.secPoint)
      .normalize();
    const v1 = new Vector3(vec.y, -vec.x, 0);
    const len = this.isClockWise ? x + r : -r - x;
    return calculatePoint(v1, len, this.xCenter);
  }

  isLoading = false;

  async finishDraw() {
    const param = this.getParams();
    try {
      if (this.isLoading) {
        return;
      }

      try {
        this.isLoading = true;
        loadEmit(true);

        const res = await wsApi.createSketchArcOfCircle(this.sketchId, param);
        const { addData } = await this.render(
          { added: res.added },
          param.annotations.some((item) => item != null),
        );

        const newCurve = addData?.curves?.find((c) => c.type === 'ArcOfCircle');

        const nextPoint = [newCurve.relative[1], newCurve.relative[2]].find(
          (p) => !param.points.includes(p),
        );

        if (this.allowContinuousCreate) {
          this.setStartPoint(nextPoint);
        }

        this.onFinishDraw?.(newCurve, nextPoint);
      } finally {
        this.isLoading = false;
        loadEmit(false);
      }
    } catch (error) {
      console.error(error);
    }
    if (!this.allowContinuousCreate) {
      this.reset();
      this.releaseObjects();
    }
  }

  getParams() {
    return {
      mode: 'three-point',
      points: this.isClockWise
        ? [this.threePoint[2], this.threePoint[1], this.threePoint[0]]
        : [this.threePoint[0], this.threePoint[1], this.threePoint[2]],
      curveStyle: this.lineType,
      constraints: this.addConstraint(),
      annotations: [dimension().addDimension()],
    };
  }

  // 添加约束
  addConstraint() {
    const constraints = [];
    if (this.startSnapPoint?.curveId) {
      constraints.push(
        this.getConstraint(this.startSnapPoint, this.startPoint, false),
      );
    }
    if (this.secSnapPoint?.curveId) {
      constraints.push(
        this.getConstraint(this.secSnapPoint, this.secPoint, false),
      );
    }
    return constraints.filter((item) => item != null);
  }
}
